package com.abe.libfitness.main.exercise;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Message;
import android.widget.ImageView;
import android.widget.TextView;

import com.abe.libcore.base.screen.OnHandlerListener;
import com.abe.libcore.utils.CommonUtils;
import com.abe.libfitness.R;
import com.abe.libfitness.R2;
import com.abe.libfitness.base.BaseComActivity;
import com.abe.libfitness.entity.ComReceiveDataBean;
import com.abe.libfitness.entity.DataEntity;
import com.abe.libfitness.entity.ExerciseEntity;
import com.abe.libfitness.main.MotorStartStopActivity;
import com.abe.libfitness.main.dialog.MotorDialog;
import com.abe.libfitness.utils.ConstantFitness;
import com.abe.libfitness.utils.ProtocolV3Utils;
import com.abe.libfitness.widget.RoundBarChartRenderer;
import com.abe.libquick.utils.NormalUtils;
import com.abe.libquick.utils.quick.EmptyUtils;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.king.view.arcseekbar.ArcSeekBar;

import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import butterknife.BindView;
import butterknife.OnClick;

public class ExerciseActivity extends BaseComActivity implements MotorDialog.OnMotorActionListener,
        ArcSeekBar.OnChangeListener, OnHandlerListener {
    private static final int BALL_HEIGHT_MAX = 400;//最大运动距离
    private static final int MIN_WEIGHT = 5;//最小力量
    private static final int MAX_WEIGHT = 50;//最大力量
    private static final int EXERCISE_CHANGE = 0x001;
    private static final int BALL_CHANGE = 0x002;
    //拉伸状态
    protected int mStatus;
    //记录单次拉伸的最大距离，计算卡路里
    protected int distance4Calorie = 0;
    @BindView(R2.id.item_count)
    TextView itemCount;
    @BindView(R2.id.item_seek_bar)
    ArcSeekBar itemSeekBar;
    @BindView(R2.id.item_weight)
    TextView itemWeight;
    @BindView(R2.id.item_calorie)
    TextView itemCalorie;
    @BindView(R2.id.item_ball_chart)
    LineChart itemBallChart;
    @BindView(R2.id.item_count_chart)
    BarChart itemCountChart;
    @BindView(R2.id.item_clear)
    ImageView itemClear;
    @BindView(R2.id.item_start_stop)
    ImageView itemStartStop;
    boolean isMotorStart;
    private MotorDialog motorDialog;
    //柱状数据
    private List<String> weights;
    private List<BarEntry> countDistances;
    //折线数据
    private List<String> times;
    private List<Entry> distances;
    //次数
    private int mRealCounts;
    //重量
    private int mShowWeight;
    private int weightSetNum;
    //卡路里
    private double calorie;
    private DataEntity dataEntity;
    private int tempHeight;

    @Override
    protected int getLayoutRes() {
        return R.layout.activity_exercise;
    }

    @Override
    protected void initContent() {
        isMotorStart = true;
        weightSetNum = 0;
        mRealCounts = 0;
        mShowWeight = MIN_WEIGHT;
        calorie = 0;
        tempHeight = 0;
        weights = new ArrayList<>();
        countDistances = new ArrayList<>();
        times = new ArrayList<>();
        distances = new ArrayList<>();
        itemCount.setText(String.valueOf(mRealCounts));
        itemWeight.setText(String.valueOf(mShowWeight));
        itemCalorie.setText(String.valueOf(calorie));
        itemSeekBar.setOnChangeListener(this);
        itemSeekBar.setMax(MAX_WEIGHT - MIN_WEIGHT);
        getHandler().postDelayed(() -> itemSeekBar.setProgress(0), 500);
        setChartStyle();
        setCountChartStyle();
    }

    private void setChartStyle() {
        itemBallChart.getDescription().setEnabled(false);
        itemBallChart.setNoDataText("");
        itemBallChart.getAxisRight().setEnabled(false);
        itemBallChart.getAxisLeft().setEnabled(false);
        itemBallChart.getLegend().setEnabled(false);
        itemBallChart.setScaleEnabled(true);
        itemBallChart.setScaleYEnabled(false);
        itemBallChart.setScaleXEnabled(true);
    }

    private void setCountChartStyle() {
        itemCountChart.getDescription().setEnabled(false);
        itemCountChart.setNoDataText("");
        itemCountChart.getAxisRight().setEnabled(false);
        itemCountChart.getAxisLeft().setEnabled(false);
        itemCountChart.getLegend().setEnabled(false);
        itemCountChart.setScaleEnabled(true);
        itemCountChart.setScaleYEnabled(false);
        itemCountChart.setScaleXEnabled(true);
        itemCountChart.setRenderer(new RoundBarChartRenderer(itemCountChart, itemCountChart.getAnimator(),
                itemCountChart.getViewPortHandler()));
    }

    private void refreshBallChart() {
        XAxis xAxis = itemBallChart.getXAxis();
        xAxis.setTextSize(14f);//设置字体大小
        xAxis.setTextColor(Color.WHITE);//设置字体颜色
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//将x轴位于底部
        xAxis.setDrawGridLines(false);//不绘制网格线
        xAxis.setGranularity(1);//间隔1
        //小技巧，通过设置Axis的最小值设置为负值，可以改变距离与Y轴的距离
        xAxis.setAxisMaximum(times.size() - 1 + 0.2f);//设置最小值
        xAxis.setAxisMinimum(-0.2f);//设置最大值
        xAxis.setLabelCount(times.size());//设置数量
        xAxis.setTextSize(12f);
        //自定义样式
        xAxis.setValueFormatter(new ValueFormatter() {

            @Override
            public String getFormattedValue(float value) {
                int pos = (int) value;
                return pos >= times.size() ? "" : times.get(pos);
            }
        });
        int lineColor = getResources().getColor(R.color.color_theme_yellow);
        LineDataSet lineDataSet = new LineDataSet(distances, "");
        lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
        lineDataSet.setColor(lineColor);
        lineDataSet.setLineWidth(2);
        lineDataSet.setDrawCircles(false);
        lineDataSet.setDrawFilled(true);
        lineDataSet.setFillColor(lineColor);
        lineDataSet.setFillAlpha(20);
        lineDataSet.setDrawHighlightIndicators(false);
        lineDataSet.setDrawValues(false);
        LineData lineData = new LineData(lineDataSet);
        itemBallChart.setData(lineData);
        if (distances.size() > 12) {
            itemBallChart.setVisibleXRange(0, 12);
            itemBallChart.moveViewToX(distances.size());
        }
        itemBallChart.invalidate();
    }

    private void refreshCountChart() {
        XAxis xAxis = itemCountChart.getXAxis();
        xAxis.setTextSize(14f);//设置字体大小
        xAxis.setTextColor(Color.WHITE);//设置字体颜色
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//将x轴位于底部
        xAxis.setDrawGridLines(false);//不绘制网格线
        xAxis.setGranularity(1);//间隔1
        //小技巧，通过设置Axis的最小值设置为负值，可以改变距离与Y轴的距离
        xAxis.setAxisMaximum(weights.size() - 1 + 0.2f);//设置最小值
        xAxis.setAxisMinimum(-0.2f);//设置最大值
        xAxis.setLabelCount(weights.size());//设置数量
        xAxis.setTextSize(12f);
        //自定义样式
        xAxis.setValueFormatter(new ValueFormatter() {

            @Override
            public String getFormattedValue(float value) {
                int pos = (int) value;
                return pos >= weights.size() ? "" : weights.get(pos);
            }
        });
        int lineColor = getResources().getColor(R.color.green_light);
        BarDataSet barDataSet = new BarDataSet(countDistances, "");
        barDataSet.setColor(lineColor);
        barDataSet.setHighlightEnabled(false);
        barDataSet.setDrawValues(false);
        BarData barData = new BarData(barDataSet);
        barData.setBarWidth(0.1f);
        itemCountChart.setFitBars(true);
        itemCountChart.setData(barData);
        if (countDistances.size() > 12) {
            itemCountChart.setVisibleXRange(0, 12);
            itemCountChart.moveViewToX(countDistances.size());
        }
        itemCountChart.invalidate();
    }

    @OnClick(R2.id.item_start_stop)
    public void startStop() {
        if (motorDialog != null && motorDialog.isShowing()) return;
        motorDialog = new MotorDialog(this, !isMotorStart, this);
        motorDialog.show();
    }

    @OnClick(R2.id.item_reduce)
    public void reduce() {
        int progress = itemSeekBar.getProgress();
        if (progress - 1 <= 0) progress = 0;
        else progress = progress - 1;
        itemSeekBar.setProgress(progress);
    }

    @OnClick(R2.id.item_add)
    public void plus() {
        int progress = itemSeekBar.getProgress();
        if (progress + 1 >= MAX_WEIGHT - MIN_WEIGHT) progress = MAX_WEIGHT - MIN_WEIGHT;
        else progress = progress + 1;
        itemSeekBar.setProgress(progress);
    }

    @OnClick(R2.id.item_clear)
    public void clear() {
        mRealCounts = 0;
        calorie = 0;
        itemCount.setText(String.valueOf(mRealCounts));
        itemCalorie.setText(String.valueOf(calorie));
        times.clear();
        distances.clear();
        weights.clear();
        countDistances.clear();
        refreshCountChart();
    }

    @Override
    public void dispatchHandleMessage(@Nullable Message message) {
        if (message == null) return;
        switch (message.what) {
            case EXERCISE_CHANGE:
                addCount(message);
                break;
            case BALL_CHANGE:
                addMove(message);
                break;
        }
    }

    private synchronized void addCount(Message message) {
        if (message == null) return;
        if (message.what == EXERCISE_CHANGE) {
            ExerciseEntity x = (ExerciseEntity) message.obj;
            if (EmptyUtils.isNotEmpty(x)) {
                weights.add(String.valueOf(x.weight));
                countDistances.add(new BarEntry(countDistances.size(), x.distance));
                itemCount.setText(String.valueOf(mRealCounts));
                refreshCountChart();
            }
        }
    }

    private synchronized void addMove(Message message) {
        float move = (float) message.obj;
        if (message.what == BALL_CHANGE) {
            if (EmptyUtils.isNotEmpty(move)) {
                times.add(NormalUtils.dateToString("mm:ss", new Date()));
                distances.add(new Entry(distances.size(), move));
                refreshBallChart();
            }
        }
    }

    @Override
    public void onStartTrackingTouch(boolean isCanDrag) {

    }

    @Override
    public void onProgressChanged(float progress, float max, boolean fromUser) {
        mShowWeight = (int) progress + MIN_WEIGHT;
        itemWeight.setText(String.valueOf(mShowWeight));
    }

    @Override
    public void onStopTrackingTouch(boolean isCanDrag) {
        mShowWeight = itemSeekBar.getProgress() + MIN_WEIGHT;
        itemWeight.setText(String.valueOf(mShowWeight));
    }

    @Override
    public void onSingleTapUp() {

    }

    @Override
    public void onAction(boolean motorStart, boolean confirm) {
        if (motorStart == isMotorStart) return;
        if (confirm) {
            Bundle bundle = new Bundle();
            bundle.putBoolean(ConstantFitness.START_MOTOR, !isMotorStart);
            gotoActivityForResult(MotorStartStopActivity.class, bundle, ConstantFitness.REQUEST_MOTOR_ACTION);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @androidx.annotation.Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) return;
        if (ConstantFitness.REQUEST_MOTOR_ACTION == requestCode) {
            isMotorStart = !isMotorStart;
        }
    }

    @Override
    protected void onDataReceived(ComReceiveDataBean ComRecData) {
        dataEntity = ProtocolV3Utils.parse(ComRecData.bRec);
        onDistance();
        if (dataEntity.getPower() != mShowWeight) {
            weightSetNum++;
            CommonUtils.INSTANCE.log("weightSetNum:" + weightSetNum);
            if (weightSetNum >= 5) {
                weightSet(mShowWeight);
                wBase("收到:" + json(ComRecData.bRec));
                weightSetNum = 0;
            }
        } else {
            weightSetNum = 0;
            wBase("收到:" + json(ComRecData.bRec));
        }
    }

    private void onDistance() {
        float move = dataEntity.getDistance() >= BALL_HEIGHT_MAX ? BALL_HEIGHT_MAX : dataEntity.getDistance();
        localSendMsg(BALL_CHANGE, move);
        //if (dataEntity.getDistance() >= BALL_HEIGHT_MAX * 0.6) { // 检测到距离大于60%最大距离时
        if (dataEntity.getDistance() >= 30) { // 检测到距离大于30
            mStatus = 1; // 拉伸状态变为1
            if (tempHeight < dataEntity.getDistance()) {
                tempHeight = dataEntity.getDistance();
            }
            if (distance4Calorie < dataEntity.getDistance()) {
                distance4Calorie = dataEntity.getDistance();
            }
        }
        // 拉伸状为1并且 检测到距离小于60%最大距离时拉伸状态变为
        //if (mStatus == 1 && dataEntity.getDistance() < BALL_HEIGHT_MAX * 0.6) {
        if (mStatus == 1 && dataEntity.getDistance() < 30) {
            mRealCounts++; // 次数 + 1
            localSendMsg(EXERCISE_CHANGE, new ExerciseEntity(dataEntity.getPower(), tempHeight));
            tempHeight = 0;
            mStatus = 0; // 拉伸状态清除
            if (distance4Calorie >= BALL_HEIGHT_MAX * 0.6 && distance4Calorie < BALL_HEIGHT_MAX * 0.8) {
                calorie = calorie + (dataEntity.getPower() / (180 + (Math.random() * 40)));
            } else if (distance4Calorie >= BALL_HEIGHT_MAX * 0.8 && distance4Calorie < BALL_HEIGHT_MAX * 1.2) {
                calorie = calorie + (dataEntity.getPower() / (130 + (Math.random() * 40)));
            } else {
                calorie = calorie + (dataEntity.getPower() / (80 + (Math.random() * 40)));
            }
        }
        runOnUiThread(() -> {
            itemCount.setText(String.valueOf(mRealCounts));
            itemCalorie.setText(String.format(Locale.CHINA, "%.1f", calorie));
        });
    }

    protected void weightSet(int weight) {
        builder.append("\n****************************力量:设置");
        builder.append(weight);
        builder.append("\n");
        builderW(ConstantFitness.LOG_FLAG_SEND);
        send(ProtocolV3Utils.writePower(weight));
    }
}